﻿using KinonekoSoftware.CodariaDB.Documents.Shenanigans;
using KinonekoSoftware.Studio.Collections;
using KinonekoSoftware.Studio.Models.Shenanigans.Talking;
using KinonekoSoftware.Studio.Pages.Shenanigans.Renderers;
using KinonekoSoftware.Studio.Utils;
using Verbose = KinonekoSoftware.Studio.Messages.Verbose;

namespace KinonekoSoftware.Studio.Pages.Shenanigans
{
    public sealed class ChannelTalkingViewModel : TabViewModelCore, IObjectBuilder<TalkingObject, TalkingMSG>
    {
        private readonly DictionaryAdapter<string, Character> _MemberSet;
        private readonly TalkingEngine                        _Engine_Talking;
        private readonly EmojiSystem                          _Engine_Icon;
        private readonly ImageSystem                          _Engine_Image;

        private ChannelTalking _channel;
        private int            _version;


        private TalkingMSG _pendingQueue;
        private string     _pendingMessageContent;
        private Character  _selectedCharacter;

        public ChannelTalkingViewModel()
        {
            Platform.GetEngine<
                TalkingEngine,
                EmojiSystem,
                ImageSystem>(out var runtime,
                             out _Engine_Talking,
                             out _Engine_Icon,
                             out _Engine_Image);

            _MemberSet       = new DictionaryAdapter<string, Character>();


            Messages = new ObservableCollection<TalkingMSG>();
            Members  = new ObservableCollection<Character>();
            Emojis   = new ObservableCollection<Emoji>();

            SaveCommand     = CreateCommand(DoSaveCommand);
            SnapshotCommand = CreateCommand(DoSnapshotCommand);

            AddMemberCommand    = CreateCommand(DoAddMemberCommand);
            EditMemberCommand   = CreateCommand<Character>(DoEditMemberCommand);
            RemoveMemberCommand = CreateCommand<Character>(DoRemoveMemberCommand);


            AddEmojiCommand        = CreateCommand(DoAddEmojiCommand);
            RemoveEmojiCommand     = CreateCommand<Emoji>(DoRemoveEmojiCommand);
            AddEmojiMessageCommand = CreateCommand<Emoji>(DoAddEmojiMessageCommand);

            SendPendingQueueCommand    = CreateCommand(DoSendPendingQueueCommand);
            AddPlainTextMessageCommand = CreateCommand(DoAddPlainTextMessageCommand);
            AddImageMessageCommand     = CreateCommand(DoAddImageMessageCommand);
            AddTipMessageCommand       = CreateCommand(DoAddTipMessageCommand);
            AddUltraTipMessageCommand  = CreateCommand(DoAddUltraTipMessageCommand);
            RemoveMessageCommand       = new FuncCommand<TalkingMSG>(DoRemoveMessageCommand);


            IsSingleton      = false;
            Removable        = true;
            EnableSafetyExit = true;
        }

        //-------------------------------------------------------------
        //
        //          Builder
        //
        //-------------------------------------------------------------


        public TalkingMSG Build(TalkingObject source)
        {
            var msg = TalkingFactory.Get(source, GetOrCache);
            msg.Update(SelectedCharacter);
            return msg;
        }

        /// <summary>
        /// 根据ID获取Character。
        /// </summary>
        /// <remarks>如果指定的Character存在，则会直接返回。否则会从TalkingEngine中获取Character。</remarks>
        /// <param name="actorID">角色的ID</param>
        /// <returns>返回操作结果，可能会返回null。</returns>
        private Character GetOrCache(string actorID)
        {
            if (string.IsNullOrEmpty(actorID))
            {
                return null;
            }

            if (!_MemberSet.TryGetValue(actorID, out var character))
            {
                character = _Engine_Talking.GetCharacter(actorID);

                //
                //
                if (character is not null)
                {
                    //
                    //
                    _MemberSet.TryAdd(character.Id, character);
                }

            }

            return character;
        }

        private void AddMSG(TalkingObject talkingObject)
        {
            if (talkingObject is null)
            {
                return;
            }

            var msg = Build(talkingObject);

            //
            //
            msg.SetCharacter(SelectedCharacter);

            //
            //
            _channel.Messages.Add(talkingObject);

            Messages.Add(msg);
        }

        private void AddOrSkip(Character character, bool loading = true)
        {
            if (character is null)
            {
                return;
            }

            var id = character.Id;

            //
            // 
            if (_MemberSet.TryAdd(id, character))
            {
                //
                // 如果不是加载阶段，则添加到Channel
                if (!loading) _channel.Members.Add(character.Id);
            }

            //
            // 修复错误
            Members.Add(character);
        }

        private async void Save()
        {
            _Engine_Talking.UpdateChannel(_channel);

            SetDeletedState(false);

            await Success(TitleSR.SuccessOperation, TextSR.Successful_Save);
        }

        //-------------------------------------------------------------
        //
        //          Override Methods
        //
        //-------------------------------------------------------------

        protected override void OnCommandProc(Verbose verbose)
        {
            if (verbose == Verbose.Save)
            {
                Save();
            }
        }

        protected override void OnReceive(PageContext context)
        {
            if (context.Has(ContextBase.Key_Value))
            {
                _channel = context.GetObject<ChannelTalking>(ContextBase.Key_Value);
            }
            else
            {
                //
                //
                InitializeWhenDebug();
            }

            base.OnReceive(context);
        }

        protected override void OnStart()
        {
            Initialize();
            base.OnStart();
        }

        protected override void OnResume()
        {
            if (_Engine_Talking.Version != _version)
            {
                // 
                // 检测当前数据是否已经删除
                SetDeletedState(!_Engine_Talking.HasChannel(_channel.Id));

                //
                //
                Initialize();
            }


            base.OnResume();
        }


        //-------------------------------------------------------------
        //
        //          Initializers
        //
        //-------------------------------------------------------------
        #region Intialize

        private void Initialize()
        {
            Members.Clear();
            Messages.Clear();


            //
            // 添加群主
            AddOrSkip(GetOrCache(_channel.OwnerID));

            //
            // 添加所有成员
            foreach (var member in _channel.Members)
            {
                AddOrSkip(GetOrCache(member));
            }

            //
            //
            SelectedCharacter = Members.First();
            PendingQueue = Build(new PlainTextTalking
            {
                Id      = ID.Get(),
                ActorID = SelectedCharacter.Id
            });

            //
            // 添加所有信息
            //
            // notice: 
            // 添加消息的时候依赖于 SelectedCharacter ，所以应该在SelectedCharacter初始化之后添加消息
            foreach (var msg in _channel.Messages
                                        .Select(Build))
            {
                //
                // add
                Messages.Add(msg);
            }

            //
            //
            Emojis.AddMany(_Engine_Talking.GetEmojis(), true);

            //
            //
            Title = _channel.Name;
            RaiseUpdated(ChannelAvatar);
            RaiseUpdated(ChannelName);
            RaiseUpdated(ChannelIntro);
            _version = _Engine_Talking.Version;
        }

        [Conditional("DEBUG")]
        private void InitializeWhenDebug()
        {
            var owner = new Character
            {
                Id     = ID.Get(),
                Avatar = "296145b233ec4647ada4d8efc51b432a",
                Name   = "Character #1",
            };

            var character2 = new Character
            {
                Id     = ID.Get(),
                Avatar = "20406813801e470490a23ed354b1ecdf",
                Name   = "Character #1",
            };

            var character3 = new Character
            {
                Id     = ID.Get(),
                Avatar = "0e8b8b86174d40408c5ad6bb3771c650",
                Name   = "Character #3",
            };

            var character4 = new Character
            {
                Id     = ID.Get(),
                Avatar = "da9b08a8b8b44aa79865659a3c0fd4a8",
                Name   = "Character #4",
            };


            _channel = new ChannelTalking
            {
                Id      = ID.Get(),
                Name    = "Test Channel Name",
                OwnerID = owner.Id,
                Members = new List<string>
                {
                    owner.Id,
                    character2.Id,
                    character3.Id,
                    character4.Id,
                },
                Messages = new List<TalkingObject>(),
            };

            _MemberSet.TryAdd(owner.Id, owner);
            _MemberSet.TryAdd(character2.Id, character2);
            _MemberSet.TryAdd(character3.Id, character3);
            _MemberSet.TryAdd(character4.Id, character4);
        }

        #endregion


        //-------------------------------------------------------------
        //
        //          Command Handlers
        //
        //-------------------------------------------------------------

        private void DoSaveCommand()
        {
            Save();
        }

        private void DoSnapshotCommand()
        {
            var context = new PageContext
            {
                Id = $"Renderer_{_channel.Id}",
            };

            context.Set(ContextBase.Key_Value, _channel);
            context.Set(ContextBase.Key_Value2, SelectedCharacter);

            GoTo<ChannelTalkingRendererViewModel>(context);
        }

        private async void DoAddMemberCommand()
        {
            var r = await CharacterPickerViewModel.Multiple(_MemberSet.OriginalHashSet);

            if (!r.IsFinished)
            {
                return;
            }

            var members = r.Value;

            foreach (var member in members)
            {
                //
                //
                AddOrSkip(member, false);

                //
                //
                AddMSG(new UltraTipTalking
                {
                    Id      = ID.Get(),
                    Mention = member.Name,
                    Tails   = "点击欢迎！",
                    Text    = "加入了本群",
                });

                //
                //
                _Engine_Talking.AddMember(member, _channel);
            }

            //
            //
            _Engine_Talking.UpdateChannel(_channel);
        }

        private async void DoEditMemberCommand(Character member)
        {
            if (member is null)
            {
                return;
            }

            if (member.Id == _channel.OwnerID)
            {
                await Danger(TitleSR.DangerOperation, "无法删除群主");
                return;
            }

            var id = member.Id;

            if (_MemberSet.Remove(id))
            {
                _channel.Members.Remove(id);
                Members.Remove(member);
            }
        }

        private async void DoRemoveMemberCommand(Character member)
        {
            if (member is null)
            {
                return;
            }

            if (member.Id == _channel.OwnerID)
            {
                await Danger(TitleSR.DangerOperation, "无法删除群主");
                return;
            }

            var id = member.Id;

            if (_MemberSet.Remove(id))
            {
                var index = Members.IndexOf(member);

                if (index == 0)
                {
                    //
                    //
                    SelectedCharacter = Members[0];
                }
                else if (index >= Members.Count)
                {
                    //
                    //
                    SelectedCharacter = Members[^1];
                }
                else
                {
                    SelectedCharacter = Members[index];
                }

                _MemberSet.Remove(id);
                _channel.Members.Remove(id);

                //
                //
                _Engine_Talking.RemoveMember(member, _channel);


                //
                //
                Members.Remove(member);

                //
                //
                AddMSG(new UltraTipTalking
                {
                    Id      = ID.Get(),
                    Mention = member.Name,
                    Text    = "移除了本群！",
                });
            }



            //
            //
            _Engine_Talking.UpdateChannel(_channel);
        }



        private async void DoAddEmojiCommand()
        {
            var r = await Platform.Emoji();

            if (!r.IsFinished)
            {
                return;
            }

            var ir = r.Value;
            var id = ir.ImageID;
            var emoji = new Emoji
            {
                Id     = ID.Get(),
                Source = id
            };

            //
            //
            await _Engine_Icon.WriteAsync(ir.ImageID, ir.ImageBuffer);

            //
            //
            _Engine_Talking.AddEmoji(emoji);
            _Engine_Icon.InsertOccupation(ir.ImageID);

            Xplat.RunOnUIThread(() =>
            {
                Emojis.Add(emoji);
            });
        }

        private void DoRemoveEmojiCommand(Emoji emoji)
        {
            if (emoji is null)
            {
                return;
            }

            //
            // 删除数据库中的表情
            _Engine_Talking.RemoveEmoji(emoji);

            //
            // 删除UI中的表情
            Emojis.Remove(emoji);


            //
            //
            SetDirtyState(true);
        }


        private async void DoSendPendingQueueCommand()
        {
            var msg = PendingQueue;

            //
            // 清除原有的PendingQueue，创建新的同类型的消息
            PendingQueue = Build(msg.Duplicate());

            if (msg is null)
            {
                return;
            }

            if (!msg.IsCompleted(out var waringMessage))
            {
                await Warning(TitleSR.WarningOperation, waringMessage);
                return;
            }

            //
            //
            msg.SetCharacter(SelectedCharacter);

            //
            //
            Messages.Add(msg);

            //
            //
            _channel.Messages.Add(msg.GetTalkingObject());

            //
            //
            SetDirtyState(true);
        }

        private void DoAddPlainTextMessageCommand()
        {
            PendingQueue = Build(new PlainTextTalking
            {
                Id = ID.Get(),
            });
        }


        private void DoAddEmojiMessageCommand(Emoji emoji)
        {
            if (emoji is null)
            {
                return;
            }


            var talking = new EmojiTalking
            {
                Id     = ID.Get(),
                Source = emoji.Source
            };
            AddMSG(talking);


            //
            //
            SetDirtyState(true);
        }


        private async void DoAddImageMessageCommand()
        {
            var r = await Platform.Thumbnail();

            if (!r.IsFinished)
            {
                return;
            }

            var ir = r.Value;
            await _Engine_Image.WriteAsync(ir.ImageID, ir.OriginBuffer);
            await _Engine_Image.WriteThumbnailAsync(ir.ImageID, ir.ImageBuffer);
            
            _Engine_Image.InsertOccupation(ir.ImageID);

            Xplat.RunOnUIThread(() =>
            {
                var talking = new ImageTalking
                {
                    Id     = ID.Get(),
                    Source = ir.ImageID,
                };
                AddMSG(talking);
            });

        }

        private void DoAddTipMessageCommand()
        {
            PendingQueue = Build(new TipTalking
            {
                Id = ID.Get(),
            });
        }

        private void DoAddUltraTipMessageCommand()
        {
            PendingQueue = Build(new UltraTipTalking
            {
                Id = ID.Get(),
            });
        }

        private void DoRemoveMessageCommand(TalkingMSG target)
        {
            if (target is null)
            {
                return;
            }

            var talkingObject = target.GetTalkingObject();
            Messages.Remove(target);

            //
            //
            _channel.Messages.Remove(talkingObject);

            //
            //
            SetDirtyState(true);

        }

        //-------------------------------------------------------------
        //
        //          Initializers
        //
        //-------------------------------------------------------------
        public Character SelectedCharacter
        {
            get => _selectedCharacter;
            set
            {
                SetValue(ref _selectedCharacter, value);

                if (_selectedCharacter is null)
                {
                    return;
                }

                foreach (var message in Messages)
                {
                    message.Update(_selectedCharacter);
                }
            }
        }

        public string ChannelIntro
        {
            get => _channel?.Intro;
            set
            {
                _channel.Intro = value;
                RaiseUpdated();
                SetDirtyState(true);
            }
        }


        public string ChannelAvatar
        {
            get => _channel?.Avatar;
            set
            {
                _channel.Avatar = value;
                RaiseUpdated();
                SetDirtyState(true);
            }
        }


        public string ChannelName
        {
            get => _channel?.Name;
            set
            {
                _channel.Name = value;
                Title         = value;
                RaiseUpdated();
                SetDirtyState(true);
            }
        }


        public string PendingMessageContent
        {
            get => _pendingMessageContent;
            set => SetValue(ref _pendingMessageContent, value);
        }

        public TalkingMSG PendingQueue
        {
            get => _pendingQueue;
            set => SetValue(ref _pendingQueue, value);
        }

        public ObservableCollection<TalkingMSG> Messages { get; }
        public ObservableCollection<Character>  Members  { get; }
        public ObservableCollection<Emoji>      Emojis   { get; }

        public ICommandEX SaveCommand     { get; }
        public ICommandEX SnapshotCommand { get; }

        public ICommandEX AddMemberCommand    { get; }
        public ICommandEX EditMemberCommand   { get; }
        public ICommandEX RemoveMemberCommand { get; }

        public ICommandEX AddEmojiCommand    { get; }
        public ICommandEX RemoveEmojiCommand { get; }


        public ICommandEX AddPlainTextMessageCommand { get; }
        public ICommandEX AddImageMessageCommand     { get; }
        public ICommandEX AddEmojiMessageCommand     { get; }
        public ICommandEX AddTipMessageCommand       { get; }
        public ICommandEX AddUltraTipMessageCommand  { get; }
        public ICommandEX RemoveMessageCommand       { get; }
        public ICommandEX SendPendingQueueCommand    { get; }
    }
}